/*
 * ScriptSelectorBox.java
 *
 * Created on December 2, 2007, 3:06 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package filecopier.gui.tabs;

import java.io.File;
import java.io.IOException;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.BorderFactory;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import filecopier.Singleton;
import filecopier.options.Options;
import filecopier.script.Script;
import filecopier.script.CopyScript;
import filecopier.script.ScriptPath;
import filecopier.gui.scripteditor.ScriptEditorDialog;
import custom.xml.DOMHelperException;
import custom.util.MostRecentlyUsed;
import custom.swing.UniqueStackComboBoxModel;

/**
 *
 * @author david
 */
public class ScriptSelectorBox extends Box implements PropertyChangeListener {

    private String browseToolTip = null;
    private String editToolTip = null;
    private String newToolTip = null;
    private int browseMnemonic = 0;
    private int editMnemonic = 0;
    private int newMnemonic = 0;
    private Options.CopyScriptType copyScriptType = null;
    private JComboBox scriptComboBox = null;
    private JButton browseBtn = null;
    private JButton editBtn = null;
    private ScriptSelectorBox ssb = this;
    private MostRecentlyUsed mru = null;
    private ScriptPath copyPath = null;

    /** Creates a new instance of ScriptSelectorBox */
    public ScriptSelectorBox(int mruIdx, final Options.CopyScriptType copyScriptType, final ScriptPath copyPath, final String browseToolTip, int browseMnemonic,
            final String editToolTip, int editMnemonic, final String newToolTip, int newMnemonic) {
        super(BoxLayout.X_AXIS);
        mru = Singleton.getInstance().getOptions().getMostRecentlyUsed()[mruIdx];
        setButtonValues(browseToolTip, browseMnemonic, editToolTip, editMnemonic, newToolTip, newMnemonic);
        this.copyPath = copyPath;
        initialize(copyScriptType);
    }

    private void initialize(final Options.CopyScriptType copyScriptType) {
        this.copyScriptType = copyScriptType;
        this.setBorder(BorderFactory.createTitledBorder(new EmptyBorder(10, 1, 10, 1),
                copyScriptType == Options.CopyScriptType.From ? "From Script:" : "To Script:"));
        chkCmdLineForScript();
        this.add(getScriptComboBox(mru.getItems()));
        this.add(Box.createRigidArea(new Dimension(4, 0)));
        this.add(getBrowseBtn());
        this.add(Box.createRigidArea(new Dimension(4, 0)));
        this.add(getEditBtn());
        if (scriptComboBox.getModel().getSize() == 0) {
            changeEditBtnText("New", newToolTip, newMnemonic);
        }
    }

    private void chkCmdLineForScript() {
        String scriptName = null;
        if (copyScriptType == Options.CopyScriptType.From) {
            scriptName = Singleton.getInstance().getOptions().getFromScriptStr();
        } else {
            scriptName = Singleton.getInstance().getOptions().getToScriptStr();
        }

        if (scriptName != null) {
            try {
                new CopyScript(new File(scriptName));
                mru.add(scriptName);
            } catch (DOMHelperException e) {
                JOptionPane.showMessageDialog(Singleton.getInstance().getFrame(), "\"" + scriptName + "\" is in an invalid format.",
                        "Invalid Script", JOptionPane.ERROR_MESSAGE);
            } catch (IOException e) {
                JOptionPane.showMessageDialog(Singleton.getInstance().getFrame(), "\"" + scriptName + "\" is in an invalid format.",
                        "Invalid Script", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private void setButtonValues(final String browseToolTip, final int browseMnemonic, final String editToolTip,
            final int editMnemonic, final String newToolTip, final int newMnemonic) {
        this.browseToolTip = browseToolTip;
        this.browseMnemonic = browseMnemonic;
        this.editToolTip = editToolTip;
        this.editMnemonic = editMnemonic;
        this.newToolTip = newToolTip;
        this.newMnemonic = newMnemonic;
    }

    private JComboBox getScriptComboBox(String[] items) {
        if (scriptComboBox == null) {
            scriptComboBox = new JComboBox(new UniqueStackComboBoxModel(items));
            scriptComboBox.setEditable(true);
            scriptComboBox.setToolTipText((copyScriptType == Options.CopyScriptType.From ? "From" : "To") + " script file path");

            // I have to set minimum and especially max sizes for the combo box to keep its height from increasing
            // when the main window is resized.
            Dimension preferredSize = scriptComboBox.getPreferredSize();
            // If I set the preferred size to the return value of getPreferredSize, the JComboBox will not autoresize. I don't
            // want it to resize, because if it does and gets larger, it can knock the buttons to the right of it off the window
            // if the window is too small to accomodate the enlarged JComboBox and the two buttons that follow it.
            scriptComboBox.setPreferredSize(preferredSize);
            scriptComboBox.setMaximumSize(new Dimension(Short.MAX_VALUE, preferredSize.height));

            scriptComboBox.addItemListener(new java.awt.event.ItemListener() {

                public void itemStateChanged(java.awt.event.ItemEvent e) {
                    if (e.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
                        // Check to see if script selected is in the list of objects kept in the
                        // scriptComboBox.
                        int ct = scriptComboBox.getItemCount();
                        boolean found = false;
                        String item = (String) e.getItem();
                        for (int i = 0; i < ct; i++) {
                            if (((String) scriptComboBox.getItemAt(i)).equals(item)) {
                                found = true;
                                break;
                            }
                        }

                        if (!found) {
                            // Item is not in list, so try to add it. If it is not a valid script, don't
                            // add it and select the first script in the scriptComboBox if it has at least
                            // one in it.
                            if (!addScriptToComboBox(new File(item))) {
                                scriptComboBox.setSelectedIndex(scriptComboBox.getItemCount() > 0 ? 0 : -1);
                            }
                        } else {
                            // Call mru.addItem here. I need to call it here in case user selected another
                            // item already in the list because if they did, it hasn't been called to put
                            // this item at the beginning of the list.
                            mru.add(item);
                        }
                    }
                }
            });
        }
        return scriptComboBox;
    }

    public JComboBox getScriptComboBox() {
        return scriptComboBox;
    }

    private Script getScript(final File file) {
        Script script = null;

        try {
            script = new CopyScript(file);
        } catch (IOException e) {
            JOptionPane.showMessageDialog(Singleton.getInstance().getFrame(), "\"" + file.getPath() + "\" is in an invalid format.",
                    "Invalid Script", JOptionPane.ERROR_MESSAGE);
            script = null;
        } catch (DOMHelperException e) {
            JOptionPane.showMessageDialog(Singleton.getInstance().getFrame(), "\"" + file.getPath() + "\" is in an invalid format.",
                    "Invalid Script", JOptionPane.ERROR_MESSAGE);
            script = null;
        }
        return script;
    }

    // Add the script to the combo box if it is a valid script.
    private boolean addScriptToComboBox(final File file) {
        boolean added = false;
        Script script = getScript(file);
        if (script != null) {
            String scriptName = script.getScriptName();
            scriptComboBox.addItem((Object) scriptName);
            // Change edit button text to "Edit" if count is 1. If scriptComboBox is empty, the edit button text
            // would be labelled "New".
            if(scriptComboBox.getItemCount() == 1) changeEditBtnText("Edit", editToolTip, editMnemonic);
            mru.add(scriptName);
            added = true;
        }
        return added;
    }

    private JButton getBrowseBtn() {
        if (browseBtn == null) {
            browseBtn = new JButton("Browse");
            browseBtn.setMnemonic(browseMnemonic);
            browseBtn.setToolTipText(browseToolTip);
            browseBtn.addActionListener(new java.awt.event.ActionListener() {

                private File lastChosenDirectory;
                private FileNameExtensionFilter fileFilter;

                // Constructor for anonymous class
                {
                    lastChosenDirectory = new File(copyPath.getPathEntryValue(0));
                    fileFilter = new FileNameExtensionFilter("Copy Script Files", "csc", getExtension());
                }

                public void actionPerformed(java.awt.event.ActionEvent e) {
                    JFileChooser fileChooser = new JFileChooser(lastChosenDirectory);
                    fileChooser.setFileFilter(fileFilter);
                    fileChooser.setFileHidingEnabled(false);

                    if (fileChooser.showOpenDialog(ssb) == JFileChooser.APPROVE_OPTION) {
                        lastChosenDirectory = fileChooser.getSelectedFile();
                        addScriptToComboBox(lastChosenDirectory);
                    }
                }
                
                private String getExtension() {
                    String extension = null;
                    if (copyScriptType == Options.CopyScriptType.To) {
                        extension = new String("tsc");
                    } else {
                        extension = new String("fsc");
                    }
                    return extension;
                }
            });
        }
        return browseBtn;
    }

    private JButton getEditBtn() {
        if (editBtn == null) {
            editBtn = new JButton("Edit");
            editBtn.setMnemonic(editMnemonic);
            editBtn.setToolTipText(editToolTip);
            editBtn.addActionListener(new java.awt.event.ActionListener() {

                public void actionPerformed(java.awt.event.ActionEvent e) {
                    String item = (String) scriptComboBox.getSelectedItem();
                    File scriptFile = item != null ? new File(item) : null;
                    Script script = null;

                    try {
                        if (scriptFile != null) {
                            script = new CopyScript(scriptFile);
                        } else {
                            script = new CopyScript();
                        }
                        new ScriptEditorDialog(copyScriptType, script, ssb, false);
                    } catch (IOException ioe) {
                        JOptionPane.showMessageDialog(Singleton.getInstance().getFrame(), ioe.getMessage(),
                                "Invalid Script", JOptionPane.ERROR_MESSAGE);

                        scriptComboBox.removeItem(item);
                    } catch (DOMHelperException dhe) {
                        JOptionPane.showMessageDialog(Singleton.getInstance().getFrame(), dhe.getMessage(),
                                "Invalid Script", JOptionPane.ERROR_MESSAGE);

                        scriptComboBox.removeItem(item);
                    }
                }
            });
        }
        return editBtn;
    }

    private void changeEditBtnText(final String text, final String toolTip, int mnemonic) {
        if (!editBtn.getText().equals(text)) {
            editBtn.setText(text);
            editBtn.setToolTipText(toolTip);
            editBtn.setMnemonic(mnemonic);
        }
    }

    public String getScriptName() {
        return ((String) scriptComboBox.getSelectedItem());
    }

    public void propertyChange(PropertyChangeEvent pce) {
        // Make sure script is valid before adding it.
        addScriptToComboBox(new File((String) pce.getNewValue()));
    }
}
